/*
 * Copyright 2022 The Open Islands Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.openislands.oi.rpc;

import org.openislands.oi.constant.Dict;
import org.openislands.oi.constant.MessageCodeEnum;
import org.openislands.oi.constant.NodeState;
import org.openislands.oi.error.LogicException;
import org.openislands.oi.manager.CommonNodeManager;
import org.openislands.oi.rpc.base.*;
import org.openislands.oi.rpc.http.HttpExtended;
import org.openislands.oi.rpc.http.HttpRequestListener;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;

@SuppressWarnings("unused")
@Component
public class NodeRoutePolicy extends RoutePolicy.DefaultRoutePolicy {
    @Value(Dict.VALUE_RETRY_NUMBER)
    private Integer retryNumber;

    @Resource
    private CommonNodeManager commonNodeManager;

    @Override
    public Object allExecutionFailed(Executor<?> executor) throws IOException {
        /*String nodeId = executor.extended().get(BaseExtended.class).getElement(BaseExtended.TARGET_MARK);
        if (!StringUtils.EMPTY.equals(nodeId)) { // local
        }*/
        return super.allExecutionFailed(executor);
    }

    @Override
    public RouteNode executionFailed(Executor<?> executor, RouteNode route, RouteNode nextRoute) {
        ItemExtended itemExtended = executor.extended().get(BaseExtended.class);
        ItemExtended.Item<Integer> retriesItem = itemExtended.getItem(BaseExtended.RETRIES_NUMBER);
        if (retriesItem == null) {
            retriesItem = BaseExtended.RETRIES_NUMBER.create(1);
            itemExtended.putItem(BaseExtended.RETRIES_NUMBER, retriesItem);
        }
        retriesItem.set(retriesItem.get() + 1);
        if (retriesItem.get() > retryNumber) return nextRoute;
        return route;
    }

    @Bean
    public HttpRequestListener nodeRoutePolicyRequestListener() {
        return (executor, clientHttpRequest) -> {
            // only verify offline nodes
            String nodeId = executor.extended().get(BaseExtended.class).getElement(BaseExtended.TARGET_MARK);
            if (commonNodeManager.queryNodeState(nodeId) != NodeState.OFFLINE) return null;
            // filter check interface
            ItemExtended itemExtended = executor.extended().get(HttpExtended.class);
            String urlPath = itemExtended.getElement(HttpExtended.URL_PATH);
            if (urlPath != null && urlPath.endsWith("/ping")) {
                // second call failed, {@link #executionFailed}
                if (executor.extended().get(BaseExtended.class).getElement(BaseExtended.RETRIES_NUMBER) == null) {
                    return null;
                }
            }
            throw new LogicException(MessageCodeEnum.CONNECT_NODE_OFFLINE_ERROR, MessageCodeEnum.CONNECT_NODE_OFFLINE_ERROR.getMessage());
        };
    }
}
